#pragma once

//Direct3D Includes
#include <d3d11.h>
#include <d3dcompiler.h>

//DirectX Tools
#include <DirectXMath.h>
#include <DirectXCollision.h>
#include <CommonStates.h>
#include <SpriteBatch.h>
#include <SpriteFont.h>
#include <WICTextureLoader.h>
using namespace DirectX;

//Tools and Utility Includes
#include "clkCollada.h"
#include "clkColor.h"
#include "clkVec2.h"
#include "clkVec3.h"
#include "clkVertex.h"
#include "clkXml.h"

//Internal and External Includes
#include "clkCamera.h"
#include "clkConstantBuffer.h"
#include "clkFont.h"
#include "clkFontInfo.h"
#include "clkMesh.h"
#include "clkMeshInfo.h"
#include "clkTexture.h"
#include "clkTextureInfo.h"
#include "clkShader.h"
#include "clkShaderInfo.h"

//Direct3D Lib Linking
#pragma comment(lib,"d3d11.lib")
#pragma comment(lib,"d3dcompiler.lib")

//DirectX Took Kit Linking
#ifdef DXTK12d
#pragma comment(lib,"DirectXTK12d.lib")
#else
#pragma comment(lib,"DirectXTK12.lib")
#endif

//Macros
#define D3D_SAFERELEASE(x) if(x){x->Release();x=0;}
#define D3D_SAFEDELETE(x)  if(x){delete x;x=0;}

//Enums
enum CLK_TEXTURES
{
	CLK_TEXTURE_CENTER,
	CLK_TEXTURE_TOPLEFT,
	CLK_TEXTURE_TOPRIGHT,
	CLK_TEXTURE_BOTLEFT,
	CLK_TEXTURE_BOTRIGHT,
};

enum CLK_FULLSCREEN
{
	CLK_FULLSCREEN_NONE,
	CLK_FULLSCREEN_ENABLE,
	CLK_FULLSCREEN_DISABLE,
};

enum CLK_DEPTHSTENCIL
{
	CLK_DEPTHSTENCIL_NONE,
	CLK_DEPTHSTENCIL_ENABLE,
	CLK_DEPTHSTENCIL_DISABLE,
};

enum CLK_RASTERIZER
{
	CLK_RASTERIZER_NONE,
	CLK_RASTERIZER_SOLID,
	CLK_RASTERIZER_WIREFRAME,
};

enum CLK_SAMPLER
{
	CLK_SAMPLER_NONE,
	CLK_SAMPLER_POINT,
};

enum CLK_ROTATE
{
	CLK_ROTATE_DEGREE,
	CLK_ROTATE_RADIAN,
	CLK_ROTATE_LOOKAT,
	CLK_ROTATE_LOOKTO,
};

class clkDirect3D11
{
protected:
	//Graphic Interfaces
	IDXGISwapChain*          m_dxgiSwapChain;
	ID3D11Device*            m_d3dDevice;
	ID3D11DeviceContext*     m_d3dDevcon;
	D3D_FEATURE_LEVEL        m_d3dFeatureLevel;
	ID3D11RenderTargetView*  m_d3dBackBuffer;
	ID3D11DepthStencilView*  m_d3dDepthBuffer;
	ID3D11Texture2D*         m_d3dBackBufferTexture;
	ID3D11Texture2D*         m_d3dDepthBufferTexture;
	SpriteBatch*             m_dtkSpriteBatch;
	
	//System Resource
	int                      m_d3dFullscreenMode;
	int                      m_d3dDepthStencilMode;
	int                      m_d3dRasterizerMode;
	int                      m_d3dSamplerMode;

	ID3D11Buffer*            m_d3dConstantBuffer;
	ID3D11Buffer*            m_d3dLineVertexBuffer;
	ID3D11DepthStencilState* m_d3dDepthStencilEnabled;
	ID3D11DepthStencilState* m_d3dDepthStencilDisabled;
	ID3D11RasterizerState*   m_d3dRasterizerSolid;
	ID3D11RasterizerState*   m_d3dRasterizerWireframe;
	ID3D11SamplerState*      m_d3dSamplerPoint;

	//User Resource Lists
	vector<clkFont*>         m_d3dFontList;
	vector<clkMesh*>         m_d3dMeshList;
	vector<clkShader*>       m_d3dShaderList;
	vector<clkTexture*>      m_d3dTextureList;

	//User Resource Paths
	string                   m_d3dFontPath;
	string                   m_d3dMeshPath;
	string                   m_d3dShaderPath;
	string                   m_d3dTexturePath;

	//User Current Resources
	clkCamera*               m_crCamera;
	clkFont*                 m_crFont;
	clkShader*               m_crShader;
	clkTexture*              m_crTexture;
public:
	clkDirect3D11();
	~clkDirect3D11();

	void initDirect3D11(
		HWND a_hwnd,
		V2DF a_dimension,
		bool a_windowed,
		bool a_vsync);
	void shutDirect3D11();
	
	void fullscreenEnable();
	void fullscreenDisable();
	void depthStencilSet(int a_mode);
	void depthStencilEnable();
	void depthStencilDisable();
	void rasterizerSet(int a_mode);
	void rasterizerSolid();
	void rasterizerWireframe();
	void samplerSet(int a_mode);
	void samplerPoint();

	bool createFont(
		clkFontInfo* a_font,
		char* a_path);
	bool createMesh(
		clkMeshInfo* a_mesh,
		char* a_path);
	bool createShader(
		clkShaderInfo* a_shader,
		char* a_path,
		char* a_vsName = 0,
		char* a_psName = 0);
	bool createTexture(
		clkTextureInfo* a_texture,
		char* a_path,
		int a_center);

	void drawMesh(
		clkMeshInfo* a_mesh,
		V3DF a_position,
		V3DF a_rotation  = V3DF(0,0,0),
		V3DF a_scaling   = V3DF(1,1,1),
		V3DF a_centering = V3DF(0,0,0),
		clkColor a_color = CLK_COLOR_WHITE,
		int a_rotateType = CLK_ROTATE_DEGREE);
	void drawTexture(
		clkTextureInfo* a_texture,
		V3DF a_position,
		V3DF a_rotation  = V3DF(0,0,0),
		V3DF a_scaling   = V3DF(1,1,1),
		V3DF a_centering = V3DF(0,0,0),
		clkColor a_color = CLK_COLOR_WHITE);
	void drawLine(
		V3DF a_start,
		V3DF a_end,
		clkColor a_color = CLK_COLOR_WHITE);
	void drawText(
		string a_text,
		V2DF a_position,
		V2DF a_scaling   = V2DF(1,1),
		V2DF a_centering = V2DF(0,0),
		float a_rotation  = 0.0f,
		clkColor a_color = CLK_COLOR_WHITE);
	void drawClear(clkColor a_color = clkColor(0.1f,0.15f,0.2f,1.0f));
	void drawPresent();

	void setFont(clkFontInfo* a_font);
	void setShader(clkShaderInfo* a_shader);
	void setTexture(clkTextureInfo* a_texture);
	void setCamera(clkCamera* a_camera);
	clkCamera* getCamera(){return m_crCamera;}

	void setFontPath(char* a_path){m_d3dFontPath=a_path;}
	void setMeshPath(char* a_path){m_d3dMeshPath=a_path;}
	void setShaderPath(char* a_path){m_d3dShaderPath=a_path;}
	void setTexturePath(char* a_path){m_d3dTexturePath=a_path;}
private:
	void initBuffers();
	void initDepthStencilStates();
	void initRasterizerStates();
	void initSamplerStates();
};